#pragma once

#include "mq_exchange.hpp"
#include "mq_queue.hpp"
#include "mq_binding.hpp"
#include "mq_message.hpp"
#include "google/protobuf/map.h"

namespace bitmq
{
    class VirtualHost
    {
    public:
        using ptr = std::shared_ptr<VirtualHost>;
        using QueueMap = std::unordered_map<std::string, MsgQueue::ptr>;

        VirtualHost(const std::string& hostname, const std::string& basedir, const std::string& dbfile)
            : _host_name(hostname)
            , _emp(std::make_shared<ExchangeManager>(dbfile))
            , _mqmp(std::make_shared<MsgQueueManager>(dbfile))
            , _bmp(std::make_shared<BindingManager>(dbfile))
            , _mmp(std::make_shared<MessageManager>(basedir))
        { 
            //交换机/队列/绑定管理类会在初始化时从数据库中恢复数据
            //但是消息管理类不会进行该操作，所以我们需要手动完成消息的历史消息恢复
            auto mq = _mqmp->getAllQueues();
            for (auto& [qname, msgqueue] : mq)
            {
                _mmp->initQueueMessage(qname);
            }
        }

        // 1）提供声明交换机的功能（存在则 OK，不存在则创建）
        bool declareExchange(const std::string& name, bitmq::ExchangeType type, 
            bool durable, bool auto_delete, const google::protobuf::Map<std::string, std::string>& args)
        {
            return _emp->declareExchange(name, type, durable, auto_delete, args);
        }

        // 2）提供删除交换机的功能（删除交换机的同时删除关联绑定信息）  
        void deleteExchange(const std::string& name)
        {
            //1.删除绑定交换机
            _emp->deleteExchange(name);
            //2.删除绑定信息
            _bmp->removeExchangeBindings(name);
        }

        // 3）判断交换机是否存在
        bool existsExchange(const std::string& ename)
        {
            return _emp->exists(ename);
        }

        // 获取指定交换机
        Exchange::ptr selectExchange(const std::string& ename)
        {
            return _emp->selectExchange(ename);
        }

        // 4）提供声明队列的功能（存在则 OK，不存在则创建，创建的同时创建队列关联消息管理对象）
        bool declareQueue(const std::string& qname, bool durable, bool exclusive, 
            bool auto_delete, google::protobuf::Map<std::string, std::string> args)
        {
            //初始化队列消息句柄（消息的存储管理）
            _mmp->initQueueMessage(qname);
            //创建队列
            return _mqmp->declareQueue(qname, durable, exclusive, auto_delete, args);
        }

        // 5）提供删除队列的功能（删除队列的同时删除关联绑定信息，删除关联消息管理对象及队列所有消息）  
        void deleteQueue(const std::string& qname)
        {
            //删除队列消息管理句柄
            _mmp->destroyQueueMessage(qname);
            //删除队列相关的绑定信息
            _bmp->removeMsgQueueBindings(qname);
            return _mqmp->deleteQueue(qname);
        }

        // 6）判断队列是否存在
        bool existsQueue(const std::string& qname)
        {
            return _mqmp->exists(qname);
        }

        QueueMap allQueues()
        {
            return _mqmp->getAllQueues();
        }

        // 7）提供交换机-队列绑定的功能
        bool bind(const std::string& ename, const std::string& qname, const std::string& key)
        {
            //绑定条件：交换机和队列必须存在）
            Exchange::ptr ep = _emp->selectExchange(ename);
            if (ep.get() == nullptr)
            {
                DLOG("进行队列绑定失败，交换机%s不存在", ename.c_str());
                return false;
            }
            MsgQueue::ptr qp = _mqmp->selectQueue(qname);
            if (qp.get() == nullptr)
            {
                DLOG("进行队列绑定失败，队列%s不存在", qname.c_str());
                return false;
            }
            //交换机是否需要持久化取决于交换机和队列是否持久化
            _bmp->bind(ename, qname, key, ep->durable && qp->durable);
            return true;
        }

        // 8）提供交换机-队列解绑的功能
        void unBind(const std::string& ename, const std::string& qname)
        {
            return _bmp->unBind(ename, qname);
        }

        // 9）判断绑定是否存在
        bool existsBinding(const std::string& ename, const std::string& qname)
        {
            return _bmp->exists(ename, qname);
        }
        
        // 10）提供获取交换机相关的所有绑定信息功能
        MsgQueueBindingMap exchangeBindings(const std::string& ename)
        {
            return _bmp->getExchangeBindings(ename);
        }

        // 11）提供新增消息的功能
        bool basicPublish(const std::string& qname, const BasicProperties* bp, const std::string& body)
        {
            MsgQueue::ptr qp = _mqmp->selectQueue(qname);
            if (qp.get() == nullptr)
            {
                DLOG("进行队列绑定失败，队列%s不存在", qname.c_str());
                return false;
            }
            return _mmp->insert(qname, bp, body, qp->durable);
        }

        // 12）提供获取指定队列队首消息的功能    
        MessagePtr basicConsume(const std::string& qname)
        {
            return _mmp->front(qname);
        }

        // 13）提供消息确认删除的功能
        void basicAck(const std::string& qname, const std::string msg_id)
        {
            return _mmp->ack(qname, msg_id);
        }

        // 14）清除
        void clear()
        {
            _emp->clear();
            _mqmp->clear();
            _bmp->clear();
            _mmp->clear();
        }

    private:
        std::string _host_name;
        ExchangeManager::ptr _emp;
        MsgQueueManager::ptr _mqmp;
        BindingManager::ptr _bmp;
        MessageManager::ptr _mmp;
    };
};